﻿#pragma once

#include <array>
#include "desCommonTools.hpp"
#include "desCommonType.hpp"

namespace des {

namespace ecp {



struct EncryptRule {
	using InitPermTable = std::array<int8, 64>;
	using InversePermTable = std::array<int8, 64>;
	using ExpandTable = std::array<int8, 48>;
	using SBoxTable = std::array<std::array<std::array<int8, 16>, 4>, 8>;
};



template <typename _rule>
concept EncryptConcept = requires {
	requires std::is_base_of_v<EncryptRule, _rule>;
	requires std::is_same_v<std::decay_t<decltype(_rule::initPermTable)>, typename _rule::InitPermTable>;
	requires std::is_same_v<std::decay_t<decltype(_rule::inversePermTable)>, typename _rule::InversePermTable>;
	requires std::is_same_v<std::decay_t<decltype(_rule::expandTable)>, typename _rule::ExpandTable>;
	requires std::is_same_v<std::decay_t<decltype(_rule::sBoxTable)>, typename _rule::SBoxTable>;
};



// 初始置换
template <typename _rule>
inline constexpr 
int64 __initialPermutation(int64 const src) {

	return __bitPermutation(src, _rule::initPermTable);
}



// 结束逆置换
template <typename _rule>
inline constexpr
int64 __inversePermutation(int64 const src) {

	return __bitPermutation(src, _rule::inversePermTable);
}



// 扩充32位一半明文到48位，优先从高位放置
template <typename _rule>
inline constexpr
int64 __halfPlaintextExpand(int32 const src) {

	return __bitPermutation((int64)((int64)src << 32), _rule::expandTable);
}



// s盒48位压缩到32位
template <typename _rule>
inline constexpr
int32 __sboxPress(int64 const src) {

	int32 res = 0;

	int64 constexpr scalar = 0x8000000000000000;
	for (int8 i = 0; i != 8; ++i) {
		int64 andOperModel = (scalar >> (6 * i));		// andOperModel
		auto m = [&src, &andOperModel](int8 n) -> int64 {
			return (src & (andOperModel >> n)) != 0;
		};
		int64 x = m(0) * 2 + m(5);
		int64 y = m(1) * 8 + m(2) * 4 + m(3) * 2 + m(4);

		// 添加结果
		res <<= 4;		// 留出空位
		res |= _rule::sBoxTable[i][x][y];		// 或上对应S盒的值
	}

	return res;
}



// 32位一半明文和48位密钥f异或操作
template <typename _rule>
inline constexpr
int32 __xorHalfPlaintextAndKey(int32 const hpt, int64 const key) {

	int64 temp = __halfPlaintextExpand<_rule>(hpt);
	temp ^= key;
	int32 res = __sboxPress<_rule>(temp);

	return res;
}



// des编码（按keys正加密一次）主函数
template <EncryptConcept _rule, typename _KeysType>
requires requires(_KeysType keys) {
	keys[0];
}
int64 desEncode(int64 const src, _KeysType const& keys) {
	
	__PlaintextBlock text;

	// 初始置换
	text.block = __initialPermutation<_rule>(src);
	
	for (int8 i = 0; i != 16; ++i) {
		int32 temp = __xorHalfPlaintextAndKey<_rule>(text.right, keys[i]);
		temp ^= text.left;

		// 左半部分直接给下一轮右半部分
		text.left = text.right;
		// 右半部分为加密异或等操作结果
		text.right = temp;
	}

	std::swap(text.left, text.right);

	// 逆置换
	text.block = __inversePermutation<_rule>(text.block);

	return text.block;
}



}
}
